#pragma once
#include <iostream>
#include <vector>

#include <cassert>

#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>

const int gmaxcap = 6;

template <class T>
class RingQueue
{
private:
    void P(sem_t &sem)
    {
        int n = sem_wait(&sem);
        if (n != 0)
            std::cout << "P操作失败" << std ::endl;
    }

    void V(sem_t &sem)
    {
        int n = sem_post(&sem);
        if (n != 0)
            std::cout << "V操作失败" << std ::endl;
    }

public:
    RingQueue(const int &queue_max_cap = gmaxcap)
        : _queue(queue_max_cap), _queue_max_cap(queue_max_cap)
    {
        // 第二个参数为0表示线程间共享，非0进程间共享
        int n = sem_init(&_spaceSem, 0, _queue_max_cap);
        assert(n == 0);
        n = sem_init(&_dataSem, 0, 0);
        assert(n == 0);

        _productorStep = _consumerStep = 0;
    }
    ~RingQueue()
    {
        sem_destroy(&_spaceSem);
        sem_destroy(&_dataSem);
    }

    // 向环形队列投递数据
    void Push(const int &in)
    {
        // 1.申请信号量,P操作。生产者预定空间资源，此时生产者生产资源
        P(_spaceSem);
        _queue[_productorStep++] = in;
        _productorStep %= _queue_max_cap;
        // 2.释放信号量,V操作。生产者释放数据资源
        V(_dataSem);
    }

    void Pop(T *out)
    {
        // 1.申请信号量,P操作。消费者预定数据资源。此时消费可以消费
        P(_dataSem);
        *out = _queue[_consumerStep++];
        _consumerStep %= _queue_max_cap;
        // 2.释放信号量,V操作。消费者释放完毕，释放空间资源
        V(_spaceSem);
    }

private:
    // 环形数组
    std::vector<T> _queue;
    size_t _queue_max_cap;
    // 两个信号量
    sem_t _spaceSem; // 生产者生产看中的空间资源的信号量
    sem_t _dataSem;  // 消费者消费看中的数据资源的信号量

    int _productorStep; // 生产生产的下标
    int _consumerStep;  // 消费者消费的下标
};